package com.cx.base.day19_thread;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author: robert.song
 * @Date: Created in 2021/8/11
 */
public class Thread_8_生产者消费者 {
    public static void main(String[] args) {
        int capcity = 10;
        int threadNum = 100;
        while (true) {
            MessageQueue mq = new MessageQueue(capcity);
            for (int i = 0; i < threadNum; i++) {
                int id = i;
                new Thread(() -> {
                    mq.put(new Message(id, "message"));
                }, "producer" + i).start();
            }
            new Thread(() -> {
                List<Message> messages = mq.take();
            }, "consumer").start();
        }
    }
}

@Slf4j(topic = "MessageQueue")
@Data
class MessageQueue {
    private LinkedList<Message> list = new LinkedList<>();
    private int capcity;

    public MessageQueue(int capcity) {
        this.capcity = capcity;
    }

    public List<Message> take() {
        synchronized (list) {
            while (list.isEmpty()) {
                try {
                    log.info("consumer wait");
                    list.wait();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //如果不是空，从队列拿数据
            List<Message> messages = new ArrayList<>();
            while (!list.isEmpty()) {
                Message message = list.removeFirst();
                messages.add(message);
                log.info("consumer used one,messageId = {}", message.getId());
            }
            log.info("consumer used all");
            list.notifyAll();
            return messages;
        }
    }

    public void put(Message message) {
        synchronized (list) {
            while (list.size() == capcity) {
                try {
                    log.info("producer wait");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.addLast(message);
            log.info("producer puted one,messageId = {}", message.getId());
            list.notifyAll();
        }
    }
}

final class Message {
    private int id;
    private Object value;

    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}
